// Sunghan Cho
// 301140084
// sunghanc@sfu.ca

#include "datafileprocessor.h"

#include <QFile>
#include <QTextStream>
#include <QStringList>
#include <QDebug>

#include "course.h"
#include "student.h"


/**********************************************************************************
  CsvDataFile
  -- Hidden class to handle the actual CSV file
**********************************************************************************/
/*
 * Handle the actual CSV file details and Course and Student extraction.
 */
class CsvDataFile
{
public:
	CsvDataFile(QString fileName);
	virtual ~CsvDataFile();

	bool isEndOfFile();
	void advanceToNextLine();

	// Return the value from this line which is the key for
	// either the course or student.
	QVariant getCourseKey();
	QVariant getStudentKey();

	// Create a new (dynamically allocated) course or student
	// from the current line of data.
	Course *createCourseFromCurrentLine();
	Student *createStudentFromCurrentLine();

private:

	QFile m_file;
	QTextStream *m_pStream;
	QStringList m_currentLineList;
};

const int CSV_COLUMN_COURSENAME = 0;
const int CSV_COLUMN_COURSESEMESTER = 1;
const int CSV_COLUMN_STUDENTNUMBER = 2;
const int CSV_COLUMN_STUDENTNAME = 3;
const int CSV_COLUMN_STUDENTPREFNAME = 4;
const int CSV_COLUMN_STUDENTEMAIL = 5;
const int CSV_COLUMN_COUNT = 6;

CsvDataFile::CsvDataFile(QString fileName)
	: m_file(fileName)
{
	m_pStream = 0;
	if (m_file.exists()) {
		m_file.open(QIODevice::ReadOnly);
		m_pStream = new QTextStream(&m_file);

		// Skip titles:
		m_pStream->readLine();
	}
}

CsvDataFile::~CsvDataFile()
{
	m_file.close();
	delete m_pStream;
}

void CsvDataFile::advanceToNextLine()
{
	QString data = m_pStream->readLine();
	qDebug() << "Data: " << data;
	m_currentLineList = data.trimmed().split(",");
}

bool CsvDataFile::isEndOfFile()
{
	bool noFile = !m_file.exists();
	bool emptyStream = (m_pStream == 0 || m_pStream->atEnd());
	return noFile || emptyStream;
}

Course* CsvDataFile::createCourseFromCurrentLine()
{
	if (m_currentLineList.length() < CSV_COLUMN_COUNT) {
		return 0;
	}

	// Extract Data:
	QString name = m_currentLineList[CSV_COLUMN_COURSENAME];
	QString semester = m_currentLineList[CSV_COLUMN_COURSESEMESTER];
	if (name.length() == 0 || semester.length() == 0) {
		return 0;
	}

	// Create the return object
	return new Course(name, semester);
}

Student* CsvDataFile::createStudentFromCurrentLine()
{
	if (m_currentLineList.length() < CSV_COLUMN_COUNT) {
		return 0;
	}

	// Extract Data:
	QString name = m_currentLineList[CSV_COLUMN_STUDENTNAME];
	QString numberStr = m_currentLineList[CSV_COLUMN_STUDENTNUMBER];
	QString email = m_currentLineList[CSV_COLUMN_STUDENTEMAIL];
	QString prefName = m_currentLineList[CSV_COLUMN_STUDENTPREFNAME];
	int studentNumber = numberStr.toInt();
	if (name.length() == 0 || numberStr.length() == 0) {
		return 0;
	}

	// Create the return object
	return new Student(name, studentNumber, email, prefName);
}

QVariant CsvDataFile::getCourseKey()
{
	if (m_currentLineList.length() < CSV_COLUMN_COUNT) {
		return QVariant();
	}
	return m_currentLineList[CSV_COLUMN_COURSENAME];
}

QVariant CsvDataFile::getStudentKey()
{
	if (m_currentLineList.length() < CSV_COLUMN_COUNT) {
		return QVariant();
	}
	return m_currentLineList[CSV_COLUMN_STUDENTNUMBER];
}



/*********************************************************************************
  DataFileProcessor Implementation
 *********************************************************************************/

DataFileProcessor::DataFileProcessor(ItemManager *pCourses, ItemManager *pStudents, QObject *parent)
	: QObject(parent)
{
	m_pCourses = pCourses;
	m_pStudents = pStudents;
}

void DataFileProcessor::processFile(QString fileName)
{
	CsvDataFile csvFile(fileName);
	while (!csvFile.isEndOfFile()) {

		// Call first because it starts before the first line.
		csvFile.advanceToNextLine();

		// Search for existing course.
		QVariant courseKey = csvFile.getCourseKey();
		Course *pCourse = dynamic_cast<Course*>(m_pCourses->findMatchingItem(courseKey));
		QVariant studentKey = csvFile.getStudentKey();
		Student *pStudent = dynamic_cast<Student*>(m_pStudents->findMatchingItem(studentKey));

		// If course does not exist, create and add it.
		if (pCourse == 0) {
			pCourse = csvFile.createCourseFromCurrentLine();
			if (pCourse == 0) {
				continue;
			}
			m_pCourses->addItem(pCourse);
		}

		// If student does not exist, create & add it.
		if (pStudent == 0) {
			pStudent = csvFile.createStudentFromCurrentLine();
			m_pStudents->addItem(pStudent);
			if (pStudent == 0) {
				continue;
			}
		}
		pStudent->addCourse(pCourse);
	}
}
